const fs = require('fs-extra')
const path = require('path')
const exec = require('child_process').exec
const execSync = require('child_process').execSync
const mm = require('micromatch')
const mkdirp = require('mkdirp')
const userid = require('userid')
const now = require('./now')
const setter = require('./HookConfigSetter')
const ConfigError = require('./HookConfigError')

function homedir (uid) {
  let username = userid.username(uid)
  let home = execSync(`getent passwd "${username}" | cut -d: -f6`, { encoding: 'UTF-8' })
  return home.trim()
}

class HookConfig {
  constructor (path, data) {
    try {
      this._path = path
      this._set(data)
    } catch (err) {
      if (err instanceof ConfigError) {
        this.error = err.message
      } else {
        throw err
      }
    }
  }

  branchMatch (branch) {
    return mm.isMatch(branch, this._branches)
  }

  exec () {
    let tNow = now()

    let command = exec(this._command, {
      cwd: this._workingDirectory,
      uid: this._uid,
      gid: this._gid,
      env: this._env()
    })

    if (this._logFile) {
      if (!fs.existsSync(this._logFile)) {
        try {
          this._createLogFile()
        } catch (err) {
          if (err.code === 'ENOENT') {
            console.log(err)
            throw new HookConfig.ExecError('创建日志文件出错，详细错误信息已记录到服务器日志。这并不一定意味着命令执行的失败，但由于缺失日志文件，从而失去了对命令执行结果的追踪。所以，务必要修复此错误。')
          } else {
            throw err
          }
        }
      }

      let logger = fs.createWriteStream(this._logFile, { flags: 'a' })
      logger.write(`新的命令执行 \`${this._command}\` at ${tNow}\n`)
      command.stdout.on('data', (data) => {
        logger.write(data)
      })
      command.stderr.on('data', (data) => {
        logger.write(data)
      })
      command.on('close', (code) => {
        if (code !== 0) {
          logger.write(`| Command exit with error code ${code}\n`)
        } 
        logger.end('\n')
      })
    }
  }

  _set (data) {
    setter.set(this, data)
  }

  _createLogFile () {
    let logFile = this._logFile
    fs.closeSync(fs.openSync(logFile, 'w'))
    fs.chmodSync(logFile, '0644')
    fs.chownSync(logFile, this._uid, this._gid)
  }

  _env () {
    let env = JSON.parse(JSON.stringify(process.env))
    env.HOME = homedir(this._uid)
    return env
  }

}

HookConfig.ExecError = class ExecError extends Error {}

module.exports = HookConfig
